Instalación y/o carga del paquete CDR
if (!require(CDR)){
if (!require(remotes)) {install.packages("remotes")}
remotes::install_github("cdr-book/CDR")
}Los datos que se utilizan en esta historia están disponibles en el paquete CDR que puede instalarse con el siguiente comando (se comprueba si no lo está):
CDRif (!require(CDR)){
if (!require(remotes)) {install.packages("remotes")}
remotes::install_github("cdr-book/CDR")
}Accidentes de tráfico en la Ciudad de Madrid registrados por Policía Municipal con víctimas y/o daños al patrimonio en el 2020. Los datos se han descargado del Portal de datos abiertos del Ayuntamiento de Madrid.)
Esta mañana estaba tan tranquilo en mi oficina (trabajo en el distrito de Chamartín para el Ayuntamiento) y me sueltan de repente: “el jefe quiere verte”. Lo primero que he pensado es que me echaban, como soy un poco “cansa almas”… Pero no, entro en el despacho del jefe… ¡Y allí está Almeida! Que ha oído que he hecho un curso de visualización en la UCLM y me he convertido en un crack de la visualización. Yo no sabía donde meterme, pero he mantenido perfectamente la compostura, como un profesional.
Así que ya me ha ido contando que está muy preocupado con los accidentes y quiere analizar el tema, para buscar soluciones. Que me agradecería mucho si encontramos dónde está el problema, para bajar el número y gravedad de los accidentes en la ciudad. El problema, me dice, es que solo me puede facilitar los datos del año 2020. Ya le he avisado de que es un año muy particular, por el estado de alarma, pero algo sacaremos…
¿Qué le interesa al alcalde? Bajar la tasa de accidentes. Pero desde el punto de vista de la visualización, está claro que va a necesitar información georreferenciada, por lo que haremos mapas. Por otro lado, seguro que la dimensión es importante, porque no es lo mismo Madrid en agosto que un día de lluvia en calendario escolar…
En cualquier caso, lo primero es hacer un análisis exploratorio para ver si hay algo raro en los datos y analizar mínimamente las variables de interés. Y después, le vamos a preparar los gráficos necesarios para aportarle conocimiento sobre los accidentes en la ciudad.
Ejercicio 1 ¿Dónde se han producido los accidentes de tráfico en Madrid en el 2020?
data(accidentes2020_data)
ggplot(data = accidentes2020_data,
aes(x = coordenada_x_utm, y = coordenada_y_utm)) +
geom_point() +
coord_fixed()Deja mucho que desear, ¿verdad?: no tenemos información, solo unos datos representados en un gráfico. Con muy poco, tirando de estética (reduciendo la dimensión de los puntos para que se vea el fondo) y alguna referencia geográfica (en forma de mapa de carreteras), veremos cómo se reduce la carga cognitiva:
accidentes2020_sf <- st_as_sf(accidentes2020_data,
coords = c("coordenada_x_utm", "coordenada_y_utm"),
crs = 25830 # proyección ETRS89/ UTM zone 30N. Área de uso: Europa
)
madrid <- esp_get_munic(munic = "^Madrid$") |>
st_transform(25830)
# descarga imagen de un de mapa estático de las carreteras de Madrid
tile <- esp_getTiles(madrid, "IDErioja", zoommin = 2)
ggplot() +
geom_spatraster_rgb(data = tile) +
geom_sf(data = accidentes2020_sf,
col = "blue", size = 0.05, alpha = 0.3) +
coord_sf(expand = FALSE) +
labs(title = "¿Dónde se producen los accidentes de tráfico en Madrid?")¡Esto ya es otra cosa! Apreciamos, lógicamente, la concentración de accidentes en el centro de la ciudad y, especialmente, en las arterias principales.
Además, como hemos comentado, tenemos conocimiento a priori sobre la influencia de la fecha en el aumento de tráfico, por lo que probablemente encontremos alguna influencia de la dimensión temporal. Vamos a verlo…
Ejercicio 2 ¿Cuándo se han producido los accidentes?
ggplot(data = accidentes2020_data,
aes(x = fecha, y = hora)) +
geom_point() +
theme_minimal()Vamos a separar la fecha y la hora, porque en ese gráfico no vemos casi nada…
# Convertir la columna 'fecha' a formato Date
accidentes2020_data$fecha <- as.Date(accidentes2020_data$fecha, format = "%d/%m/%Y")
accidentes2020_fecha <- accidentes2020_data |>
select(fecha) |>
group_by(fecha) |>
mutate(n = n()) |>
unique()
ggplot(data = accidentes2020_fecha,
aes(x = fecha, y = n)) +
geom_line() +
theme_minimal()Como ya le advertimos al alcalde, el año 2020 no es bueno para sacar conclusiones. Ya le hemos pedido que nos facilite datos más amplios para poder proporcionarle una mejor visualización del número de accidentes por fecha, pero mientras tanto, nos tendremos que arreglar con lo que tenemos…
# Convertir la columna 'hora' a formato Date
accidentes2020_data$hora_dia <- hour(as.POSIXct(accidentes2020_data$hora, format = "%H:%M:%S"))
accidentes2020_hora_dia <- accidentes2020_data |>
select(hora_dia) |>
group_by(hora_dia) |>
mutate(n = n()) |>
unique()
ggplot(data = accidentes2020_hora_dia,
aes(x = hora_dia, y = n)) +
geom_line() +
theme_minimal()Es evidente que la hora punta a mediodía y en la salida del trabajo, a las 14 y las 19 horas del día son los 2 picos a vigilar. Pero este gráfico tiene un gran margen de mejora. Hala, a trabajar un poquito y a dejarlo “niquelao”, que ya sabéis muchas cosas, cracks:
Completa las partes del código señaladas por _____ o xxxxx para obtener el resultado propuesto.
ggplot(data = accidentes2020_hora_dia,
aes(x = hora_dia, y = n)) +
geom_xxxx(linewidth = 1, color = "orange") +
labs(_____ = "Número de accidentes según la franja horaria del día",
subtitle = "Las 14 y las 19 horas presentan el mayor número de accidentes",
x = "Hora del día", y = "Número de accidentes en la franja horaria") +
scale_y__________(labels = function(x) {
format(x,
big.mark = ".", decimal.mark = ",", scientific = FALSE
)
}) +
theme________() +
theme(axis.title.x = element_____(hjust = 0),
axis.title.y = element_text(hjust = 1))Ejercicio 3 ¿De qué tipo son los accidentes?
tipo_accidente n porcentaje
<fctr> <int> <num>
1: Alcance 7294 22.4936010
2: Atropello a animal 75 0.2312887
3: Atropello a persona 2127 6.5593487
4: Caída 2118 6.5315940
5: Choque contra obstáculo fijo 4667 14.3923274
6: Colisión frontal 899 2.7723810
7: Colisión fronto-lateral 8081 24.9205909
8: Colisión lateral 4386 13.5257656
9: Colisión múltiple 2231 6.8800691
10: Despeñamiento 2 0.0061677
11: Otro 251 0.7740463
12: Solo salida de la vía 151 0.4656613
13: Vuelco 145 0.4471582
¿Qué le pasa a este gráfico? ¿En que se puede mejorar?
Ejercicio 4 ¿Existe asociación entre el sexo y el tipo de persona (conductor, pasajero, peaton) que sufre el accidente?
# accidentes2020_data_sin_na <- accidentes2020_data |>
# na.omit()
balloonplot(table(accidentes2020_data$sexo , accidentes2020_data$tipo_persona))Ejercicio 5 ¿Existe asociación entre el sexo y el tipo de accidente?
accidentes2020_data |>
ggplot() +
geom_mosaic(aes(x = product(tipo_accidente, sexo),
fill=sexo)) niveles <- levels(factor(accidentes2020_data$tipo_accidente))
etiquetas <- set_names(str_wrap(niveles, width = 20),
niveles)
accidentes2020_data |>
ggplot(aes(sexo, fill = estado_meteorológico)) +
facet_wrap(vars(tipo_accidente),
labeller = as_labeller(etiquetas)) +
geom_bar() +
labs(fill = "Estado Meteorológico") +
theme(axis.text.x = element_text(angle = 90)) +
theme_minimal()# con la librería leflet podemos crear un mapa interactivo
utm_crs <- "+proj=utm +zone=30 +datum=WGS84 +units=m +no_defs"
accidentes_sf <- st_as_sf(accidentes2020_data,
coords = c("coordenada_x_utm", "coordenada_y_utm"), crs = utm_crs)
accidentes_sf <- st_transform(accidentes_sf, crs = 4326)
accidentes2020_data$longitude <- st_coordinates(accidentes_sf)[, 1]
accidentes2020_data$latitude <- st_coordinates(accidentes_sf)[, 2]
leaflet(data = accidentes2020_data) %>%
addTiles() %>%
addCircleMarkers(lng = ~longitude, lat = ~latitude,
radius = 2, color = "red", opacity = 0.5) %>%
addProviderTiles(providers$Esri.WorldImagery)accidentes2020_sf <- st_transform(accidentes2020_sf, crs = 4326)
accidentes2020_data$longitude <- st_coordinates(accidentes2020_sf)[, 1]
accidentes2020_data$latitude <- st_coordinates(accidentes2020_sf)[, 2]
leaflet(data = accidentes2020_data) %>%
addTiles() %>%
addCircleMarkers(lng = ~longitude, lat = ~latitude,
radius = 1, color = "red", opacity = 0.5) # addProviderTiles(providers$Esri.WorldImagery)leaflet(data = accidentes2020_data) %>%
addTiles() %>%
addCircleMarkers(lng = ~longitude, lat = ~latitude,
radius = 2, color = "red", opacity = 0.5, clusterOptions = markerClusterOptions())# ahora haz un mapa de calor
leaflet(data = accidentes2020_data) %>%
addTiles() %>%
addHeatmap(lng = ~longitude, lat = ~latitude, blur = 20, max = 0.05)Ejercicio 6 ¿Dónde se registraron los accidentes el día de la declaración del Estado de Alarma en Madrid?
# Convertir la columna 'fecha' a formato Date
accidentes2020_data[, fecha := as.Date(fecha, format = "%d/%m/%Y")]
# Definir el rango de fechas del estado de alarma
fecha_inicio <- as.Date("2020-03-14")
fecha_fin <- as.Date("2020-03-14")
# Filtrar el dataset por el rango de fechas
estado_alarma_data <- accidentes2020_data[fecha >= fecha_inicio & fecha <= fecha_fin]
# Crear un mapa con los accidentes
leaflet(data = estado_alarma_data) %>%
addTiles() %>%
addCircleMarkers(lng = ~longitude, lat = ~latitude,
radius = 3, color = "red", opacity = 0.5)